package com.ruoyi.login;

import com.alibaba.fastjson.JSON;
import com.ruoyi.appletsutil.AppletsLoginUtils;
import com.ruoyi.appletsutil.ResultCode;
import com.ruoyi.appletsutil.UnAuthorizedException;
import com.ruoyi.common.annotation.UnAuth;
import com.ruoyi.common.constant.Rediskey;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.RandomMathLetter;
import com.ruoyi.common.utils.SnowflakeIdWorker;
import com.ruoyi.common.utils.WeChatAppletUtils;
import com.ruoyi.common.utils.WechatUtils;
import com.ruoyi.common.utils.bean.AccessTokenResult;
import com.ruoyi.common.utils.bean.WeChatAppletLoginResponse;
import com.ruoyi.common.utils.bean.WechatSetting;
import com.ruoyi.member.domain.UmsMember;
import com.ruoyi.member.service.IUmsMemberService;
import com.ruoyi.member.service.LoginService;
import com.ruoyi.member.service.WeChatAppletLoginService;
import com.ruoyi.member.vo.AppletLoginInfo;
import com.ruoyi.member.vo.AppletLoginRedisParamResponse;
import com.ruoyi.member.vo.LoginParams;
import com.ruoyi.setting.bean.WechatPaySet;
import com.ruoyi.setting.service.ILsPaySettingService;
import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 登录控制器
 *
 * @author SK
 * @since 2018/6/13
 */
@Controller
@Slf4j
@Api(description = "登录接口")
public class LoginController {

    /**
     * 注入微信小程序登录服务
     */
    @Autowired
    private WeChatAppletLoginService weChatAppletLoginService;

    /**
     * 注入redis服务
     */
    @Autowired
    private RedisCache redisService;

    /**
     * jwt密钥
     */
    @Value("${token.secret}")
    private String jwtSecretKey;

    /**
     * 注入登录处理service
     */
    @Resource(name = "loginService")
    private LoginService loginService;


    /**
     * 注入随机数生成器
     */
    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;
    /**
     * 注入支付设置服务
     */
    @Autowired
    private ILsPaySettingService paySetService;
    @Autowired
    private IUmsMemberService memberService;
    /**
     * 会员登录
     *
     * @param loginParams 登录参数
     * @return -1 用户名或密码错误  -2 账号冻结  -3 账号锁定 1 成功  -4 验证码错误
     */
    @PostMapping("/loginByPassword")
    @UnAuth
    @ResponseBody
    @ApiOperation(value = "会员登录", notes = "会员登录（不需要认证）")
    @ApiResponses({
            @ApiResponse(code = 200, message = "result: -1 用户名或密码错误  -2 账号冻结  -3 账号锁定 1 成功  -4 验证码错误  token:放登录成功后的token", response = Map.class)
    })
    public AjaxResult loginByPassword(@RequestBody LoginParams loginParams, HttpServletRequest request) {
        // 登录结果
        return loginService.login(loginParams);
    }
    /**
     * 会员登录
     *
     * @param loginParams 登录参数
     * @return -1 用户名或密码错误  -2 账号冻结  -3 账号锁定 1 成功  -4 验证码错误
     */
    @PostMapping("/logout")
    @UnAuth
    @ResponseBody
    @ApiOperation(value = "会员登录", notes = "会员登录（不需要认证）")
    @ApiResponses({
            @ApiResponse(code = 200, message = "result: -1 用户名或密码错误  -2 账号冻结  -3 账号锁定 1 成功  -4 验证码错误  token:放登录成功后的token", response = Map.class)
    })
    public AjaxResult logout(@RequestBody LoginParams loginParams, HttpServletRequest request) {
        redisService.deleteObject(getToken(request));

        return AjaxResult.success();
    }
    /**
     * 公众号通过code登录
     *
     * @param 。开发者需要在开发者服务器后台调用 api，使用 code 换取 openid 和 session_key 等信息
     * @return 登录信息
     */
    @UnAuth
    @ResponseBody
    @RequestMapping("/loginByWeiXinCode")
    @ApiOperation(value = "小程序获取登录信息", notes = "小程序获取登录信息（不需要认证）", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "form", dataType = "string", name = "code", value = "用户登录凭证"),
    })
    @ApiResponses({
            @ApiResponse(code = 200, message = "登录信息", response = AppletLoginInfo.class)
    })
    public AjaxResult loginByWeiXinCode(String code ,long storeId , HttpServletRequest request) {
        final StringBuilder sb = new StringBuilder();
        log.info("getLoginInfo :checkAppletOAuthParams code="+code);
        Map<String, Object> res = new HashMap<>();
        WechatPaySet wechatAppletPaySet = paySetService.queryPaySet(storeId).getWechatPaySet();
        WechatSetting wechatSetting = new WechatSetting();
        wechatSetting.setAppId(wechatAppletPaySet.getAppId());
        wechatSetting.setAppSecret(wechatAppletPaySet.getAppSecret());
        if (!wechatSetting.checkAppletOAuthParams()) {
            log.error("getLoginInfo fail:checkAppletOAuthParams fail");
            return AjaxResult.error("getLoginInfo fail:checkAppletOAuthParams fail");
        }
        WeChatAppletLoginResponse weChatAppletLoginResponse = WechatUtils.getLoginInfo(code, wechatSetting);
        if (Objects.isNull(weChatAppletLoginResponse)) {
            log.error("getLoginInfo fail: getLoginInfo fail");
            return AjaxResult.error("getLoginInfo fail: getLoginInfo fail");
        }

        log.info("getOpenId : openid=="+weChatAppletLoginResponse.getOpenid());
        AppletLoginRedisParamResponse appletLoginRedisParamResponse = new AppletLoginRedisParamResponse();
        UmsMember member =memberService.queryCustomerByh5OpenId(weChatAppletLoginResponse.getOpenid());
        if (member!=null){
            appletLoginRedisParamResponse.setCustomerId(member.getId());
            appletLoginRedisParamResponse.setToken(sb.toString());
            res.put("member", member);
        }else {
            member = new UmsMember();
            member.setSource("5");
            member.setMobile(RandomMathLetter.randomInt(11));
            member.setPassword("123456");
            member.setNickname("魔金"+ RandomMathLetter.randomString(4));
            //member.setImage(weChatAppletLoginResponse.);
            member.setH5OpenId(weChatAppletLoginResponse.getOpenid());
            memberService.insertUmsMember(member);
            res.put("member", member);
        }
        sb.append(Jwts.builder().setSubject(member.getUsername())
                .compressWith(CompressionCodecs.DEFLATE)
                .signWith(SignatureAlgorithm.HS256, jwtSecretKey)
                .setIssuedAt(new Date())
                .claim("userName", member.getUsername())
                .claim("nickName", member.getNickname())
                .claim("releName", member.getRelename())
                .claim("id", member.getId())
                .setExpiration(Date.from(Instant.now().plus(1, ChronoUnit.HOURS))) // 有效期1小时
                .compact());
        appletLoginRedisParamResponse.setToken(sb.toString());
        redisService.putToRedis(String.format(Rediskey.TOKEN, sb.toString()), JSON.toJSONString(member));
        res.put("access_token", sb.toString());
        res.put("refresh_token", sb.toString());
        return AjaxResult.success(res);
    }
    /**
     * 小程序获取openid 并更新当前用户，也就是手机登录后小程序授权
     *
     * @param 。开发者需要在开发者服务器后台调用 api，使用 code 换取 openid 和 session_key 等信息
     * @return 登录信息
     */
    @UnAuth
    @ResponseBody
    @RequestMapping("/getOpenId")
    @ApiOperation(value = "小程序获取登录信息", notes = "小程序获取登录信息（不需要认证）", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "form", dataType = "string", name = "code", value = "用户登录凭证"),
    })
    @ApiResponses({
            @ApiResponse(code = 200, message = "登录信息", response = AppletLoginInfo.class)
    })
    public AjaxResult getOpenId(@RequestBody  AppletLoginRedisParamResponse appletLoginRedisParamResponse , HttpServletRequest request) {

        WechatPaySet wechatAppletPaySet = paySetService.queryPaySet(appletLoginRedisParamResponse.getStoreId()).getWechatAppletPaySet();
        WechatSetting wechatSetting = new WechatSetting();
        wechatSetting.setAppId(wechatAppletPaySet.getAppId());
        wechatSetting.setAppSecret(wechatAppletPaySet.getAppSecret());
        if (!wechatSetting.checkAppletOAuthParams()) {
            log.error("getLoginInfo fail:checkAppletOAuthParams fail");
            return AjaxResult.error("getLoginInfo fail:checkAppletOAuthParams fail");
        }
        WeChatAppletLoginResponse weChatAppletLoginResponse = WeChatAppletUtils.getLoginInfo(appletLoginRedisParamResponse.getCode(), wechatSetting);
        if (Objects.isNull(weChatAppletLoginResponse)) {
            log.error("getLoginInfo fail: getLoginInfo fail");
            return AjaxResult.error("getLoginInfo fail: getLoginInfo fail");
        }
       UmsMember member = new UmsMember();
        log.info("getOpenId : openid=="+weChatAppletLoginResponse.getOpenid());
        member.setAppletOpenId(weChatAppletLoginResponse.getOpenid());
        long customerId = AppletsLoginUtils.getInstance().getCustomerId(request);
        member.setId(customerId);
        return AjaxResult.success(memberService.updateUmsMember(member));
    }
    /**
     * 检测token
     *
     */
    @RequestMapping("/verifyToken")
    @UnAuth
    @ResponseBody
    public AjaxResult verifyToken(String token, HttpServletRequest request) {

        return AjaxResult.success();
    }
    /**
     * 小程序登录
     *
     * @param  。开发者需要在开发者服务器后台调用 api，使用 code 换取 openid 和 session_key 等信息
     * @return 登录信息
     */
    @UnAuth
    @ResponseBody
    @RequestMapping("/mpWechatLogin")
    @ApiOperation(value = "小程序获取登录信息", notes = "小程序获取登录信息（不需要认证）", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "form", dataType = "string", name = "code", value = "用户登录凭证"),
    })
    @ApiResponses({
            @ApiResponse(code = 200, message = "登录信息", response = AppletLoginInfo.class)
    })
    public AjaxResult mpWechatLogin(@RequestBody  AppletLoginRedisParamResponse appletLoginRedisParamResponse , HttpServletRequest request) {
        final StringBuilder sb = new StringBuilder();

        Map<String, Object> res = new HashMap<>();

        WechatPaySet wechatAppletPaySet = paySetService.queryPaySet(appletLoginRedisParamResponse.getStoreId()).getWechatAppletPaySet();
        WechatSetting wechatSetting = new WechatSetting();
        wechatSetting.setAppId(wechatAppletPaySet.getAppId());
        wechatSetting.setAppSecret(wechatAppletPaySet.getAppSecret());
        if (!wechatSetting.checkAppletOAuthParams()) {
            log.error("getLoginInfo fail:checkAppletOAuthParams fail");
            return AjaxResult.error("getLoginInfo fail:checkAppletOAuthParams fail");
        }
        WeChatAppletLoginResponse weChatAppletLoginResponse = WeChatAppletUtils.getLoginInfo(appletLoginRedisParamResponse.getCode(), wechatSetting);
        if (Objects.isNull(weChatAppletLoginResponse)) {
            log.error("getLoginInfo fail: getLoginInfo fail");
            return AjaxResult.error("getLoginInfo fail: getLoginInfo fail");
        }
        appletLoginRedisParamResponse.setSessionKey(weChatAppletLoginResponse.getSession_key());
        appletLoginRedisParamResponse.setOpenId(weChatAppletLoginResponse.getOpenid());
        UmsMember member =memberService.queryCustomerByappletOpenId(weChatAppletLoginResponse.getOpenid());
        if (member!=null){
            appletLoginRedisParamResponse.setCustomerId(member.getId());
            appletLoginRedisParamResponse.setToken(sb.toString());
            res.put("member", member);
        }else {
            member = new UmsMember();
            member.setSource("5");
            member.setMobile(RandomMathLetter.randomInt(11));
            member.setPassword("123456");
            member.setNickname("魔金"+ RandomMathLetter.randomString(4));
            member.setAppletOpenId(weChatAppletLoginResponse.getOpenid());
            memberService.insertUmsMember(member);
            res.put("member", member);
        }
        sb.append(Jwts.builder().setSubject(member.getUsername())
                .compressWith(CompressionCodecs.DEFLATE)
                .signWith(SignatureAlgorithm.HS256, jwtSecretKey)
                .setIssuedAt(new Date())
                .claim("userName", member.getUsername())
                .claim("nickName", member.getNickname())
                .claim("releName", member.getRelename())
                .claim("id", member.getId())
                .setExpiration(Date.from(Instant.now().plus(1, ChronoUnit.HOURS))) // 有效期1小时
                .compact());
        appletLoginRedisParamResponse.setToken(sb.toString());
        redisService.putToRedis(String.format(Rediskey.TOKEN, sb.toString()), JSON.toJSONString(member));

        res.put("access_token", sb.toString());
        res.put("refresh_token", sb.toString());
        return AjaxResult.success(res);

    }

    /**
     * 绑定公众号
     */
    @GetMapping("/wechatlogin")
    @UnAuth
    @ApiIgnore
    public void wechatLogin(String code, String state, long storeId ,HttpServletResponse response, HttpServletRequest request) throws Exception {
        log.debug("wechatLogin and code:{} \r\n state:{} \r\n ", code, state);
        WechatPaySet wechatAppletPaySet = paySetService.queryPaySet(storeId).getWechatPaySet();
        WechatSetting wechatSetting = new WechatSetting();
        wechatSetting.setAppId(wechatAppletPaySet.getAppId());
        wechatSetting.setAppSecret(wechatAppletPaySet.getAppSecret());
        wechatSetting.setUrl(wechatAppletPaySet.getLoginNotice());

        //获取accesstoken
        AccessTokenResult weChatAppletLoginResponse = WechatUtils.getAccessToken(code, state, wechatSetting);
        if (ObjectUtils.isEmpty(weChatAppletLoginResponse) || weChatAppletLoginResponse.isError()) {
            log.error("wechatLogin error : getAccessToken fail");
        }
        UmsMember member =memberService.queryCustomerByh5OpenId(weChatAppletLoginResponse.getOpenid());
        if (member!=null){

        }else {
            member = memberService.queryCustomerWithNoPasswordById(AppletsLoginUtils.getInstance().getCustomerId(request));
            if (member!=null){
                member.setH5OpenId(weChatAppletLoginResponse.getOpenid());
                memberService.updateUmsMember(member);
            }
        }
        response.sendRedirect(state);
    }






    /**
     * 获取token
     *
     * @param request request
     * @return token
     */
    private String getToken(HttpServletRequest request) {
        // 认证信息在header 中的key
        final String authHeader = request.getHeader("Authorization");

        if (Objects.isNull(authHeader) || !authHeader.startsWith("Bearer")) {
            log.info("getClaims fail :Authorization fail ");
            throw new UnAuthorizedException(ResultCode.WX_NOT_AUTHORIZED);
        }
        return authHeader.length() >= 7 ? authHeader.substring(7) : authHeader.substring(6);
    }



}
